package com.example.ass7;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.example.ass7.helper.Convertor;

/**
 * @author Meirav Ben Izhak
 */
public class HighScoresTable {

    private int size;
    private final List<ScoreInfo> scores;

    // Create an empty high-scores table with the specified size.
    // The size means that the table holds up to size top scores.
    /**
     * @param size
     *            size
     */
    public HighScoresTable(
        int size) {
        this.size = size;
        this.scores = new ArrayList<ScoreInfo>();
    }

    // Add a high-score.
    /**
     * @param score
     *            score
     */
    public void add(ScoreInfo score) {
        this.scores.add(score);
        this.size++;
    }

    // Return table size.
    /**
     * @return int
     */
    public int size() {
        return this.size;
    }

    // Return the current high scores.
    // The list is sorted such that the highest
    // scores come first.
    /**
     * @return List<ScoreInfo>
     */
    public List<ScoreInfo> getHighScores() {
        return this.scores;
    }

    // return the rank of the current score: where will it
    // be on the list if added?
    // Rank 1 means the score will be highest on the list.
    // Rank `size` means the score will be lowest.
    // Rank > `size` means the score is too low and will not
    // be added to the list.
    /**
     * @param score
     *            score
     * @return int
     */
    public int getRank(int score) {
        Collections.sort(this.scores, new Comparator<ScoreInfo>() {
            @Override
            public int compare(ScoreInfo scoreInfo1,
                    ScoreInfo scoreInfo2) {
                return Integer.valueOf(scoreInfo1.getScore()).compareTo(
                        scoreInfo2.getScore());
            }
        });
        for (int rank = 0; rank < this.scores.size(); rank++) {
            ScoreInfo info = this.scores.get(rank);
            if (info.getScore() > score) {
                return rank + 1;
            }
        }
        return this.scores.size();
    }

    // Clears the table
    /**
     * void.
     */
    public void clear() {
        this.scores.clear();
        this.size = 0;
    }

    // Load table data from file.
    // Current table data is cleared.
    /**
     * @param filename
     *            filename
     * @throws IOException
     *             IOException
     */
    public void load(File filename) throws IOException {
        this.clear();
        BufferedReader br = null;

        try {
            br = new BufferedReader(new FileReader(filename));
            int justSize = Convertor.parseInt(br.readLine());
            for (int index = 0; index < justSize; index++) {
                String name = br.readLine();
                int score = Convertor.parseInt(br.readLine());
                ScoreInfo info = new ScoreInfo(name, score);
                this.scores.add(info);
            }

        } catch (IOException e) {
            System.out.println(e);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    // Save table data to the specified file.
    /**
     * @param filename
     *            filename
     * @throws IOException
     *             IOException
     */
    public void save(File filename) throws IOException {
        try {
            Collections.sort(scores, new Comparator<ScoreInfo>() {

                @Override
                public int compare(ScoreInfo o1, ScoreInfo o2) {
                    return Integer.valueOf(o2.getScore())
                            .compareTo(o1.getScore());
                }

            });

            FileWriter fw = new FileWriter(filename.getAbsoluteFile());
            // BufferedWriter bw = new BufferedWriter(fw);
            fw.write(String.valueOf(this.size));
            fw.write("\n");
            for (ScoreInfo info : this.scores) {
                fw.write(info.getName());
                fw.write("\n");
                fw.write(String.valueOf(info.getScore()));
                fw.write("\n");
            }

            fw.close();

            System.out.println("Save file done");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Read a table from file and return it.
    // If the file does not exist, or there is a problem with
    // reading it, an empty table is returned.
    /**
     * @param filename
     *            filename
     * @return HighScoresTable
     */
    public static HighScoresTable loadFromFile(File filename) {
        HighScoresTable table = new HighScoresTable(0);
        BufferedReader br = null;

        try {
            br = new BufferedReader(new FileReader(filename));
            int justSize = Convertor.parseInt(br.readLine());
            for (int index = 0; index < 5; index++) {
                String name = br.readLine();
                if (name == null) {
                    return table;
                }
                int score = Convertor.parseInt(br.readLine());
                ScoreInfo info = new ScoreInfo(name, score);
                table.add(info);
            }

        } catch (IOException e) {
            System.out.println(e);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return table;
    }
}
